{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "https://python.langchain.com/docs/how_to/tools_prompting/\n",
    "![](./image/tool2.png)\n",
    "\n",
    "选择工具后执行工具调用，并输出工具信息及执行结果"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "5ae9806959ff27df"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "multiply(x: float, y: float) -> float - Multiply two numbers together.\n",
      "add(x: int, y: int) -> int - Add two numbers.\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.tools import render_text_description, tool\n",
    "\n",
    "\n",
    "@tool\n",
    "def multiply(x: float, y: float) -> float:\n",
    "    \"\"\"Multiply two numbers together.\"\"\"\n",
    "    return x * y\n",
    "\n",
    "\n",
    "@tool\n",
    "def add(x: int, y: int) -> int:\n",
    "    \"\"\"Add two numbers.\"\"\"\n",
    "    return x + y\n",
    "\n",
    "\n",
    "tools = [multiply, add]\n",
    "rendered_tools = render_text_description(tools)\n",
    "print(rendered_tools)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:28:34.846867Z",
     "start_time": "2024-10-31T03:28:34.831380Z"
    }
   },
   "id": "2671c159d3b1f20b",
   "execution_count": 19
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "{'name': 'add', 'arguments': {'x': 3, 'y': 1132}}"
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.output_parsers import JsonOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "import os\n",
    "from langchain_openai import ChatOpenAI\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()\n",
    "llm = ChatOpenAI(\n",
    "    # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key=\"sk-xxx\",\n",
    "    openai_api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "    openai_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "    model_name=\"qwen-max\",\n",
    "    max_retries=0,\n",
    ")\n",
    "\n",
    "system_prompt = f\"\"\"\\\n",
    "You are an assistant that has access to the following set of tools. \n",
    "Here are the names and descriptions for each tool:\n",
    "\n",
    "{rendered_tools}\n",
    "\n",
    "Given the user input, return the name and input of the tool to use. \n",
    "Return your response as a JSON blob with 'name' and 'arguments' keys.\n",
    "\n",
    "The `arguments` should be a dictionary, with keys corresponding \n",
    "to the argument names and the values corresponding to the requested values.\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [(\"system\", system_prompt), (\"user\", \"{input}\")]\n",
    ")\n",
    "chain = prompt | llm | JsonOutputParser()\n",
    "\n",
    "chain.invoke({\"input\": \"what's 3 plus 1132\"})\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:28:37.647161Z",
     "start_time": "2024-10-31T03:28:34.849916Z"
    }
   },
   "id": "b5e4198b5cd9b218",
   "execution_count": 20
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 调用工具\n",
    "既然模型可以请求调用工具，我们需要编写一个可以实际调用工具的函数。\n",
    "该函数将通过名称选择适当的工具，并将模型选择的参数传递给它。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "4dc9d40d9a23d880"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "15.0"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from typing import Any, Dict, Optional, TypedDict\n",
    "\n",
    "from langchain_core.runnables import RunnableConfig\n",
    "\n",
    "\n",
    "class ToolCallRequest(TypedDict):\n",
    "    \"\"\"A typed dict that shows the inputs into the invoke_tool function.\"\"\"\n",
    "\n",
    "    name: str\n",
    "    arguments: Dict[str, Any]\n",
    "\n",
    "\n",
    "def invoke_tool(\n",
    "    tool_call_request: ToolCallRequest, config: Optional[RunnableConfig] = None\n",
    "):\n",
    "    \"\"\"A function that we can use the perform a tool invocation.\n",
    "\n",
    "    Args:\n",
    "        tool_call_request: a dict that contains the keys name and arguments.\n",
    "            The name must match the name of a tool that exists.\n",
    "            The arguments are the arguments to that tool.\n",
    "        config: This is configuration information that LangChain uses that contains\n",
    "            things like callbacks, metadata, etc.See LCEL documentation about RunnableConfig.\n",
    "\n",
    "    Returns:\n",
    "        output from the requested tool\n",
    "    \"\"\"\n",
    "    tool_name_to_tool = {tool_tmp.name: tool_tmp for tool_tmp in tools}\n",
    "    name = tool_call_request[\"name\"]\n",
    "    requested_tool = tool_name_to_tool[name]\n",
    "    return requested_tool.invoke(tool_call_request[\"arguments\"], config=config)\n",
    "\n",
    "invoke_tool({\"name\": \"multiply\", \"arguments\": {\"x\": 3, \"y\": 5}})"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:28:37.658656Z",
     "start_time": "2024-10-31T03:28:37.649162Z"
    }
   },
   "id": "171365e8cbd917b7",
   "execution_count": 21
  },
  {
   "cell_type": "markdown",
   "source": [
    "重新微调chain，把invoke_tool加入调用链中，并将工具类输出返回"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "a723f3dd481c30ec"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "{'name': 'add', 'arguments': {'x': 3, 'y': 1132}, 'tool_output': 1135}"
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "\n",
    "chain = prompt | llm | JsonOutputParser()|RunnablePassthrough.assign(tool_output=invoke_tool)\n",
    "\n",
    "chain.invoke({\"input\": \"what's 3 plus 1132\"})"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:29:03.267948Z",
     "start_time": "2024-10-31T03:29:00.483407Z"
    }
   },
   "id": "d0f5680b4b789702",
   "execution_count": 23
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
